package org.myspringframework.aop.framework.autoproxy;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.myspringframework.aop.Advisor;
import org.myspringframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.myspringframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.myspringframework.beans.factory.ListableBeanFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class BeanFactoryAspectJAdvisorsBuilder {

    private ListableBeanFactory beanFactory;


    //扫描所有bean下带有@Aspect的bean，并转换为Advisor切面
    public List<Advisor> buildAspectJAdvisors(){
        List<Advisor> result=new ArrayList<>();

        //获取所有添加了@Aspect的bean
        List<Object> aspectBeans=new ArrayList<>();
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            Class<?> clazz = beanFactory.getType(beanDefinitionName);
            if (clazz.isAnnotationPresent(Aspect.class)){
                Object bean = beanFactory.getBean(beanDefinitionName);
                aspectBeans.add(bean);
            }
        }

        for (Object bean : aspectBeans) {
                //有@Aspect,处理其下的切点和通知方法
                //遍历所有方法
                Method[] methods = bean.getClass().getMethods();
                //寻找加了@Before的方法
                for (Method method : methods) {
                    if (method.isAnnotationPresent(Before.class)){
                        //当前方法加了@Before注解
                        Before before = method.getAnnotation(Before.class);
                        //获取注解属性的切点表达式
                        String value = before.value();

                        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
                        AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, bean.getClass());
                        advisor.setExpression(value);
                        advisor.setAdvice(advice);

                        result.add(advisor);
                    }
                    //todo:添加了其他注解的方法@After @Around @AfterReturning @AfterThrowing
                }

        }
        return result;
    }

    public void setBeanFactory(ListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
}
